package tiku_service

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

var defaultSetting = map[string]interface{}{
	"scene":            "sit",                   // 姿态            # sit
	"action_enable":    false,                   // 动作触发        # False
	"resolution":       "-",                     // 分辨率            # video: 720x1280； pc_video: 1920x1080
	"scene_bg_url":     "",                      // 背景url        # None
	"tts_source":       "microsoft",             // TTS            # microsoft
	"version":          "zp_digital_human_v1.1", // 形象版本        # zp_digital_human_v1.1
	"output_fmt":       "mp4",                   // 输出格式        # mp4
	"priority":         100,                     // 优先级            # 1
	"emotion":          "smile",                 // 情绪            # smile
	"camera":           "-",                     // 相机机位        # video: sit_9_16； pc_video: sit_27_0_16_9
	"scene_brooch_url": "",                      // 胸针            # None
	"static_frames":    0,                       // 结尾静止帧数    # 0
	"suit":             "suit_v2",               // 上衣            # suit_v2
	"suit_color":       "0F1216",                // 上衣颜色        # 0F1216
	"pants":            "suit_v2",               // 裤子            # suit_v2
	"pants_color":      "0F1216",                // 裤子颜色        # 0F1216
	"voice_color":      "zh-CN-XiaoxiaoNeural",  // 音色            # zh-CN-XiaoxiaoNeural
	"voice_speed":      0,                       // 语速            # 0
	"face":             "HZB",                   // 形象            # HZB
	"hair":             "ponytail",              // 发型            # ponytail
}
var (
	baseDomain = "http://117.50.185.132:8080/dihum"
	userName   = "admin"
	password   = "123456"
)

func getMd5(s string) string {
	h := md5.New()
	h.Write([]byte(s))
	md5Str := hex.EncodeToString(h.Sum(nil))
	return md5Str
}

func sendQuery(url string, reqJsonData []byte, appId, secret string) (*http.Response, error) {
	xDate := time.Now().Format("2006-01-02 15:04:05")
	// 生成md5
	md5Str := getMd5(fmt.Sprintf("%s%s", appId, xDate))

	hmacObj := hmac.New(sha1.New, []byte(secret))
	hmacObj.Write([]byte(md5Str))
	hashing := hex.EncodeToString(hmacObj.Sum([]byte("")))

	headers := map[string]string{
		"X-date": xDate,
		"signa":  hashing,
		"appid":  appId,
	}
	req, err := http.NewRequest("POST", url, bytes.NewReader(reqJsonData))
	if err != nil {
		return nil, err
	}
	for k, v := range headers {
		req.Header.Set(k, v)
	}

	client := http.Client{
		Timeout: 60 * time.Second,
	}
	resp, err := client.Do(req)
	return resp, err
}

func getSecret() (appId, secret string) {
	uri := "/api/user/login"
	body := map[string]interface{}{
		"username": userName,
		"password": getMd5(password),
	}
	bodyData, _ := json.Marshal(body)
	resp, err := sendQuery(baseDomain+uri, bodyData, "", "")
	if err != nil {
		fmt.Println(fmt.Sprintf("send:%s error:%+v", uri, err))
		return
	}
	type respStruct struct {
		Data struct {
			AppId  string `json:"appid"`
			Secret string `json:"secret"`
		} `json:"data"`
	}
	r := &respStruct{}

	defer resp.Body.Close()
	respData, _ := io.ReadAll(resp.Body)
	err = json.Unmarshal(respData, r)
	if err != nil {
		fmt.Printf("Unmarshal body error data:%s, err:%+v \n", respData, err)
		return
	}
	appId = r.Data.AppId
	secret = r.Data.Secret
	return
}

func CreateTask(data string, resolution string) (string, error) {
	if strings.TrimSpace(data) == "" {
		return "", nil
	}
	uri := "/api/task/new"

	appId, secret := getSecret()

	body := defaultSetting
	if resolution == "s" { // 竖屏
		body["resolution"] = "720x1280"
		body["camera"] = "sit_9_16"
	} else {
		body["resolution"] = "1920x1080"
		body["camera"] = "sit_27_0_16_9"
	}
	body["text"] = strings.TrimSpace(data)
	bodyData, _ := json.Marshal([]map[string]interface{}{body})

	resp, err := sendQuery(baseDomain+uri, bodyData, appId, secret)
	if err != nil {
		fmt.Println(fmt.Sprintf("send:%s error:%+v", uri, err))
		return "", err
	}
	type respStruct struct {
		Data []struct {
			TaskId string `json:"task_id"`
		} `json:"data"`
	}
	r := &respStruct{}
	defer resp.Body.Close()
	respData, _ := io.ReadAll(resp.Body)
	err = json.Unmarshal(respData, r)
	if err != nil {
		fmt.Printf("Unmarshal body error data:%s, err:%+v \n", respData, err)
		return "", err
	}
	if len(r.Data) == 0 {
		return "", errors.New("response data is null")
	}
	return r.Data[0].TaskId, nil
}

func GetTask(taskId string) (string, error) {
	uri := "/api/task/list"
	appId, secret := getSecret()
	body := map[string]map[string]string{
		"params": {
			"query": taskId,
		},
	}
	bodyData, _ := json.Marshal(body)
	resp, err := sendQuery(baseDomain+uri, bodyData, appId, secret)
	if err != nil {
		fmt.Println(fmt.Sprintf("send:%s error:%+v", uri, err))
		return "", err
	}
	type respStruct struct {
		Data struct {
			List []struct {
				Url string `json:"url"`
			} `json:"list"`
		} `json:"data"`
	}
	r := &respStruct{}
	defer resp.Body.Close()
	respData, _ := io.ReadAll(resp.Body)
	err = json.Unmarshal(respData, r)
	if err != nil {
		fmt.Printf("Unmarshal body error data:%s, err:%+v \n", respData, err)
		return "", err
	}
	if len(r.Data.List) == 0 {
		return "", errors.New("response data is null")
	}
	return r.Data.List[0].Url, nil

}
